213. 打家劫舍 II

213. 打家劫舍 II

Similar Question

Solution Tips

方案一: 动态规划

Since House[1] and House[n] are adjacent, they cannot be robbed together. Therefore, the problem becomes to rob either House[1]-House[n-1] or House[2]-House[n], depending on which choice offers more money. Now the problem has degenerated to the House Robber, which is already been solved.

var rob = function(nums) {
    // 1. 定义 dp[i] 为偷前 i 家, 能获得最大价值
    // 与 1 最大区别就是围成了一圈, 要不从两边同时开始偷 ? 这样参考对撞指针, 相撞了就可以判断?
    // 又或者在最后一个的时候, 判断一下? 如果是第 0 家已经偷过了, 就不能偷了

    const dp = Array.from({ length: nums.length }, () => 0);
    if (nums.length === 1) {
        return nums[0];
    }
    dp[0] = nums[0];
    // 一定偷第一家
    dp[1] = nums[0];
    for (let i = 2; i < nums.length; i++) {
        // 根据 dp[i] 的定义, 如果不偷这一家的收益更大, 那么就不应该偷的
        dp[i] = Math.max(nums[i] + dp[i - 2], dp[i - 1]);
    }
    dp[nums.length - 1] = dp[nums.length - 2];
    // 到目前为止都是和 1 相同的, 在最后这里做一个特判
    // 因为 dp[-1] 肯定是没有影响的, 只需要考虑 dp[0], 就行了
    // 可以走两圈, 一圈是不偷第一家, 这样最后一家就肯定可以偷了
    // 第二圈是偷第一家, 这样最后一家就肯定不偷, 最后一家不偷, 那就是 dp[-2]

    console.log(dp.concat());

    const dp2 = Array.from({ length: nums.length }, () => 0);
    if (nums.length === 1) {
        return nums[0];
    }
    // 不偷第一家
    dp2[0] = 0;
    dp2[1] = nums[1];
    for (let i = 2; i < nums.length; i++) {
        // 根据 dp2[i] 的定义, 如果不偷这一家的收益更大, 那么就不应该偷的
        dp2[i] = Math.max(nums[i] + dp2[i - 2], dp2[i - 1]);
    }
    console.log(dp2.concat());
    // return dp[0] > dp[1] ? dp[nums.length - 2] : dp[nums.length - 1];
    return Math.max(dp[nums.length - 1], dp2[nums.length - 1]);
};
// console.log(rob([2,3,2]));
console.log(rob([1,2,3]));

方案一: 优化

var rob = function(nums) {
    const length = nums.length;
    if (length === 1) {
        return nums[0];
    } else if (length === 2) {
        return Math.max(nums[0], nums[1]);
    }
    return Math.max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1));
};

const robRange = (nums, start, end) => {
    let first = nums[start], second = Math.max(nums[start], nums[start + 1]);
    for (let i = start + 2; i <= end; i++) {
        const temp = second;
        second = Math.max(first + nums[i], second);
        first = temp;
    }
    return second;
}